package com.rpframework.module.common.bottom.service.impl;

import com.rpframework.core.json.EmptyException;
import com.rpframework.core.json.LoginExpiredException;
import com.rpframework.module.common.bottom.entity.AdminUser;
import com.rpframework.module.common.bottom.entity.Authentication;
import com.rpframework.module.common.bottom.entity.Jurisdiction;
import com.rpframework.module.common.bottom.entity.JurisdictionUri;
import com.rpframework.module.common.bottom.entity.enums.RequestType;
import com.rpframework.module.common.bottom.mapper.JurisdictionMapper;
import com.rpframework.module.common.bottom.service.AdminUserService;
import com.rpframework.module.common.bottom.service.AuthenticationService;
import com.rpframework.module.common.bottom.service.JurisdictionService;
import com.rpframework.module.common.bottom.service.JurisdictionUriService;
import com.rpframework.utils.ArrayUtils;
import com.rpframework.utils.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 默认实现 Created by jump on 2016/7/4.
 */
@Service
public class JurisdictionServiceImpl extends BaseServiceImpl<Jurisdiction> implements JurisdictionService {

    private final JurisdictionUriService jurisdictionUriService;
    private final AdminUserService adminUserService;
    private final AuthenticationService authenticationService;

    private static List<Jurisdiction> jurisdictions;

    JurisdictionMapper mapper;

    @Autowired
    public JurisdictionServiceImpl(JurisdictionMapper mapper, JurisdictionUriService jurisdictionUriService, AdminUserService adminUserService,
                                   AuthenticationService authenticationService) {
        super(mapper);
        this.mapper = mapper;
        this.jurisdictionUriService = jurisdictionUriService;
        this.adminUserService = adminUserService;
        this.authenticationService = authenticationService;
    }

    private List<Jurisdiction> getJurisdictions() {
        if (jurisdictions == null) jurisdictions = Jurisdiction.dBParseView(selectUrl());
        return jurisdictions;
    }

    @Override
    public Long getHeadJurisdictionId(Jurisdiction entity) {
        String[] uri = entity.getUri();
        if (ArrayUtils.isEmpty(uri)) return null;

        RequestType requestType = entity.getRequestType();
        JurisdictionUri jurisdictionUri = new JurisdictionUri();
        jurisdictionUri.setUri(uri[0]);

        List<JurisdictionUri> us = jurisdictionUriService.select(jurisdictionUri);
        if (us.isEmpty()) return null;

        List<Long> id = us.stream().map(JurisdictionUri::getJurisdictionId).collect(Collectors.toList());

        List<Jurisdiction> jurisdictions = selectsByIds(id);

        for (Jurisdiction ju : jurisdictions) {
            if (ju.getRequestType().equals(requestType)) return ju.getId();
        }

        return null;
    }

    @Override
    public Long testUriExistence(String uri) {
        for (Jurisdiction p : getJurisdictions()) {
            List<Jurisdiction> urlDescribes = p.getUrlDescribes();
            if (urlDescribes != null) {
                for (Jurisdiction c : urlDescribes) {
                    List<JurisdictionUri> jurisdictionUris = p.getJurisdictionUris();
                    List<JurisdictionUri> jurisdictionUrisC = c.getJurisdictionUris();
                    for (JurisdictionUri jp : jurisdictionUris) {
                        for (JurisdictionUri jc : jurisdictionUrisC) {
                            if (Objects.equals(jp.getUri() + jc.getUri(), uri)) {
                                return c.getId();
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    @Override
    public void add(Jurisdiction entity) {
        String head = "";
        if (!ArrayUtils.isEmpty(entity.getUri())) head = entity.getUri()[0];

        List<Jurisdiction> urlDescribes = entity.getUrlDescribes();
        if (!CollectionUtils.isEmpty(urlDescribes)) {
            for (Jurisdiction ju : urlDescribes) {
                boolean flg = false;
                String[] uri = ju.getUri();
                Long proId = null;

                if (!ArrayUtils.isEmpty(uri)) {
                    for (String u : uri) {
                        if (!getUriJurisdictionIdExt(head + u, ju.getRequestType())) {
                            Long headJurisdictionId = getHeadJurisdictionId(entity);
                            if (headJurisdictionId == null) {
                                insertOne(entity);
                                JurisdictionUri jurisdictionUri = new JurisdictionUri();
                                jurisdictionUri.setUri(head);
                                jurisdictionUri.setJurisdictionId(entity.getId());
                                jurisdictionUriService.insertOne(jurisdictionUri);
                                add(entity);
                                flg = true;
                                break;
                            } else {
                                if (proId == null) {
                                    ju.setFixId(headJurisdictionId);
                                    insertOne(ju);
                                    proId = ju.getId();
                                }

                                JurisdictionUri jurisdictionUri = new JurisdictionUri();
                                jurisdictionUri.setUri(u);
                                jurisdictionUri.setJurisdictionId(proId);
                                jurisdictionUriService.insertOne(jurisdictionUri);
                            }
                        }
                    }
                }
                if (flg) break;
            }
        }
    }

    @Override
    public void adds(List<Jurisdiction> entityList) {
        if (!CollectionUtils.isEmpty(entityList)) {
            entityList.forEach(this::add);
        }
        jurisdictions = Jurisdiction.dBParseView(selectUrl());
    }

    @Override
    public boolean hasAuth(Long userId, String uri) {
        AdminUser adminUser = adminUserService.selectByPrimaryKey(userId);
        if (adminUser == null) throw new LoginExpiredException("用户不存在");
        Long roleId = adminUser.getRoleId();
        return hasAuthByRole(roleId, uri);
    }

    @Override
    public boolean hasAuthByRole(Long roleId, String uri) {
        if (roleId == null) throw new LoginExpiredException("无此权限");
        Long existence = testUriExistence(uri);
        if (existence == null) throw new EmptyException("地址不存在");
        Authentication authentication = new Authentication();
        authentication.setRoleId(roleId);
        authentication.setJurisdictionId(existence);
        return authenticationService.selectCount(authentication) > 0;
    }

    @Override
    public Long[] getUriJurisdictionId(String url, RequestType type) {
        List<Long> us = new ArrayList<>();
        for (Jurisdiction p : getJurisdictions()) {
            List<Jurisdiction> urlDescribes = p.getUrlDescribes();
            if (urlDescribes != null) {
                for (Jurisdiction c : urlDescribes) {
                    List<JurisdictionUri> jurisdictionUris = p.getJurisdictionUris();
                    List<JurisdictionUri> jurisdictionUrisC = c.getJurisdictionUris();
                    for (JurisdictionUri jp : jurisdictionUris) {
                        us.addAll(jurisdictionUrisC.stream().filter(
                                jc -> Objects.equals(jp.getUri() + jc.getUri(), url) && type.equals(c.getRequestType())).map(
                                jc -> c.getId()).collect(Collectors.toList()));
                    }
                }
            }
        }
        if (us.isEmpty()) return null;
        Long[] id = new Long[us.size()];
        us.toArray(id);
        return id;
    }

    @Override
    public boolean getUriJurisdictionIdExt(String url, RequestType type) {
        return getUriJurisdictionId(url, type) != null;
    }

    private List<JurisdictionUri> getJurisdictionUris(String uri) {
        JurisdictionUri jurisdictionUri = new JurisdictionUri();
        jurisdictionUri.setUri(uri);
        return jurisdictionUriService.select(jurisdictionUri);
    }

    @Override
    public Example getExample() {
        return new Example(Jurisdiction.class);
    }

    @Override
    public List<Jurisdiction> selectUrl() {
        return mapper.selectUrl();
    }
}
